/***************************************************************************************** 
*                                     TinyRtos51 
*                                The Real-Time Kernel 
*                              Copyright(c) 2024 fanxsp
*                         SPDX-License-Identifier: APACHE-2.0
*       This software is subject to an open source license and is distributed by fanxsp,
*       pursuant to the terms of the Apache License.
******************************************************************************************/
/***************************************************************************************** 
* 				TinyRtos51 OSSFlag.c
* Author: fanxsp 
* Revision: 1.00
* Date: 2023-09-16
* 
******************************************************************************************/
#define __IN_EFLAG_C
#include "tinyrtos51.h"

#if OSEFLAGS > 0

/* 每个EFLAG占用1 byte */
OStypeInt8u OSLOC_EFLAG OSEFlagArea[OSEFLAGS] ;

/* API */
/******************************************************************************************
* 初始化事件标志 在OSStart()前调用
* 参数：eID  事件标志ID   value 初始值
*******************************************************************************************/
void OSInitEFlag(OStypeInt8u eID,OStypeInt8u value) 
{
#if OSENABLE_ERROR_CHECKING > 0
	if(eID > OSEFLAGS-1) return ;
#endif
	OSEFlagArea[eID] = value  ;
}

/********************************************************************************************
* 等待事件标志(掩码中的任意位)  在任务中调用 不能在中断中调用
* 参数：eID  事件标志ID  mask 掩码  ticks 超时时间  =0 为永久等待
*********************************************************************************************/
#if OSBYTES_OF_DELAYS > 0
void OSWaitEFlagAny(OStypeInt8u eID,OStypeInt8u mask,OStypeOfDelays ticks) 
#else
void OSWaitEFlagAny(OStypeInt8u eID,OStypeInt8u mask) 	
#endif
{
#if OSENABLE_ERROR_CHECKING > 0
	if(eID > OSEFLAGS-1) return ;
#endif

	OSEnterCritical() ;
#if OSBYTES_OF_DELAYS > 0
	OSTcbArea[OSTaskRunning].timeout = 0 ;
	while((OSEFlagArea[eID] & mask) == 0 && OSTcbArea[OSTaskRunning].timeout == 0)
#else
	while((OSEFlagArea[eID] & mask) == 0)
#endif
	{
		OSTcbArea[OSTaskRunning].state = OSTCB_WAITING ;
#if OSBYTES_OF_DELAYS > 0
		OSTcbArea[OSTaskRunning].delay = ticks ;
		SP++ ;
		*(OStypeOfDelays idata *)SP = ticks ;
#if OSBYTES_OF_DELAYS > 1
		SP++ ;
#endif
#endif
//		SP++ ;
//		*(OStypeInt8u idata *)SP = mask ;
//		SP++ ;
//		*(OStypeInt8u idata *)SP = eID ;
		ACC = mask ;
		_push_(ACC) ;
		ACC = eID ;
		_push_(ACC) ;
		OSDelFromList(OSTaskRunning) ;
		eID = *(OStypeInt8u idata *)SP ;
		OSAppendToList(OSHeadEFlag(eID),OSTaskRunning) ;
		OSTaskSw() ;
//		eID = *(OStypeInt8u idata *)SP ;
//		SP-- ;
//		mask = *(OStypeInt8u idata *)SP ;
//		SP-- ;
		_pop_(ACC) ;
		eID = ACC ;
		_pop_(ACC) ;
		mask = ACC ;
#if OSBYTES_OF_DELAYS > 0
#if OSBYTES_OF_DELAYS > 1
		SP-- ;
#endif
		ticks = *(OStypeOfDelays idata *)SP ;
		SP-- ;
#endif
	}
	OSExitCritical() ;
}

/************************************************************************************************
* 等待事件标志(掩码中的所有位)  在任务中调用 不能在中断中调用
* 参数：eID  事件标志ID  mask 掩码  ticks 超时时间  =0 为永久等待
************************************************************************************************/
#if OSBYTES_OF_DELAYS > 0
void OSWaitEFlagAll(OStypeInt8u eID,OStypeInt8u mask,OStypeOfDelays ticks) 
#else
void OSWaitEFlagAll(OStypeInt8u eID,OStypeInt8u mask) 	
#endif
{
#if OSENABLE_ERROR_CHECKING > 0
	if(eID > OSEFLAGS-1) return ;
#endif

	OSEnterCritical() ;
#if OSBYTES_OF_DELAYS > 0
	OSTcbArea[OSTaskRunning].timeout = 0 ;
	while((OSEFlagArea[eID] & mask) != mask && OSTcbArea[OSTaskRunning].timeout == 0)
#else
	while((OSEFlagArea[eID] & mask) != mask)
#endif
	{
		OSTcbArea[OSTaskRunning].state = OSTCB_WAITING ;
#if OSBYTES_OF_DELAYS > 0
		OSTcbArea[OSTaskRunning].delay = ticks ;
		SP++ ;
		*(OStypeOfDelays idata *)SP = ticks ;
#if OSBYTES_OF_DELAYS > 1
		SP++ ;
#endif
#endif
//		SP++ ;
//		*(OStypeInt8u idata *)SP = mask ;
//		SP++ ;
//		*(OStypeInt8u idata *)SP = eID ;
		ACC = mask ;
		_push_(ACC) ;
		ACC = eID ;
		_push_(ACC) ;
		OSDelFromList(OSTaskRunning) ;
		eID = *(OStypeInt8u idata *)SP ;
		OSAppendToList(OSHeadEFlag(eID),OSTaskRunning) ;
		OSTaskSw() ;
//		eID = *(OStypeInt8u idata *)SP ;
//		SP-- ;
//		mask = *(OStypeInt8u idata *)SP ;
//		SP-- ;
		_pop_(ACC) ;
		eID = ACC ;
		_pop_(ACC) ;
		mask = ACC ;
#if OSBYTES_OF_DELAYS > 0
#if OSBYTES_OF_DELAYS > 1
		SP-- ;
#endif
		ticks = *(OStypeOfDelays idata *)SP ;
		SP-- ;
#endif
	}
	OSExitCritical() ;
}

/************************************************************************************************
* 等待事件标志(和掩码精确匹配)  在任务中调用 不能在中断中调用
* 参数：eID  事件标志ID  mask 掩码  ticks 超时时间  =0 为永久等待
*************************************************************************************************/
#if OSBYTES_OF_DELAYS > 0
void OSWaitEFlagExact(OStypeInt8u eID,OStypeInt8u mask,OStypeOfDelays ticks) 
#else
void OSWaitEFlagExact(OStypeInt8u eID,OStypeInt8u mask) 	
#endif
{
#if OSENABLE_ERROR_CHECKING > 0
	if(eID > OSEFLAGS-1) return ;
#endif

	OSEnterCritical() ;
#if OSBYTES_OF_DELAYS > 0
	OSTcbArea[OSTaskRunning].timeout = 0 ;
	while(OSEFlagArea[eID] != mask && OSTcbArea[OSTaskRunning].timeout == 0)
#else
	while(OSEFlagArea[eID] != mask)
#endif
	{
		OSTcbArea[OSTaskRunning].state = OSTCB_WAITING ;
#if OSBYTES_OF_DELAYS > 0
		OSTcbArea[OSTaskRunning].delay = ticks ;
		SP++ ;
		*(OStypeOfDelays idata *)SP = ticks ;
#if OSBYTES_OF_DELAYS > 1
		SP++ ;
#endif
#endif
//		SP++ ;
//		*(OStypeInt8u idata *)SP = mask ;
//		SP++ ;
//		*(OStypeInt8u idata *)SP = eID ;
		ACC = mask ;
		_push_(ACC) ;
		ACC = eID ;
		_push_(ACC) ;
		OSDelFromList(OSTaskRunning) ;
		eID = *(OStypeInt8u idata *)SP ;
		OSAppendToList(OSHeadEFlag(eID),OSTaskRunning) ;
		OSTaskSw() ;
//		eID = *(OStypeInt8u idata *)SP ;
//		SP-- ;
//		mask = *(OStypeInt8u idata *)SP ;
//		SP-- ;
		_pop_(ACC) ;
		eID = ACC ;
		_pop_(ACC) ;
		mask = ACC ;
#if OSBYTES_OF_DELAYS > 0
#if OSBYTES_OF_DELAYS > 1
		SP-- ;
#endif
		ticks = *(OStypeOfDelays idata *)SP ;
		SP-- ;
#endif
	}
	OSExitCritical() ;
}

/***********************************************************************************************
* 读取事件标志值 不清零  可以在中断中调用
* 参数：eID  事件标志IDID 
* 返回：事件标志值
************************************************************************************************/
OStypeInt8u OSReadEFlag(OStypeInt8u eID) 
{
#if OSENABLE_ERROR_CHECKING > 0
	if(eID > OSEFLAGS-1)  return 0 ;
#endif
	return OSEFlagArea[eID]  ;
}

/***********************************************************************************************
* 设置事件标志 公共代码  不含临界保护 不能直接调用 
* 参数：eID 事件标志ID  mask 掩码
***********************************************************************************************/
void OSSetEFlag(OStypeInt8u eID,OStypeInt8u mask) 
{
	OStypeInt8u i,tmp ;

	OSEFlagArea[eID] |= mask ;
	i= OSListArea[OSHeadEFlag(eID)].prev ;
	while(i != OSHeadEFlag(eID))
	{
		OSTcbArea[i].state = OSTCB_ELIGIBLE ;
#if OSBYTES_OF_DELAYS > 0
		OSTcbArea[i].delay = 0 ;
#endif
//		ACC = eID ;
//		_push_(ACC) ;
//		ACC = OSListArea[i].prev ;
//		_push_(ACC) ;
		tmp = OSListArea[i].prev ;
		OSAppendToList(OSHeadEligible,i) ;
//		_pop_(ACC) ;
//		i = ACC ;
//		_pop_(ACC) ;
//		eID = ACC ;
		i = tmp ;
	}
	OSListArea[OSHeadEFlag(eID)].prev = OSHeadEFlag(eID) ;
	OSListArea[OSHeadEFlag(eID)].next = OSHeadEFlag(eID) ;
}

/***********************************************************************************************
* 在任务中设置事件标志  
* 参数：eID  事件标志ID  mask 掩码 
***********************************************************************************************/
void OSTaskSetEFlag(OStypeInt8u eID, OStypeInt8u mask) 
{
#if OSENABLE_ERROR_CHECKING > 0
	if(eID > OSEFLAGS-1) return ;
#endif
	OSEnterCritical() ;
	OSSetEFlag(eID,mask) ;
#if OSMETHOD > 0
	OSTaskSw() ;
#endif
	OSExitCritical() ;
}

/***********************************************************************************************
* 在中断中设置事件标志  
* 参数：eID 事件标志ID  mask 掩码
***********************************************************************************************/
void OSIntSetEFlag(OStypeInt8u eID,OStypeInt8u mask) 
{
#if OSENABLE_ERROR_CHECKING > 0
	if(eID > OSEFLAGS-1) return ;
#endif
	OSEnterCritical() ;
	OSSetEFlag(eID,mask) ;
#if OSMETHOD > 0
	OSPendSVAct() ;
#endif
	OSExitCritical() ;
}

/************************************************************************************************
* 清零事件标志 清零不会使任务就绪 可以在中断中调用
* 参数：eID  事件标志ID  mask 掩码 
************************************************************************************************/
void OSClrEFlag(OStypeInt8u eID, OStypeInt8u mask) 
{
	OSEnterCritical() ;
	OSEFlagArea[eID] &= ~mask ;
	OSExitCritical() ;
}

#endif

